package monopoly;

import monopoly.ui.GameBoard;
import monopoly.ui.GameBoardSpace;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;


public class Player {
	
	private String name;
	private int boardPosition;
	private double balance;
	private boolean isActive;
	private Token token;
	private int rollCount;
	private boolean isInJail;
	private Railroad[] railroadsOwned;
	private int railroadCount;
	private Utility[] utilitiesOwned;
	private int utilityCount;
	private StreetProperty[][] streetPropertiesOwned;
	private int[] streetPropertyCount;
	private int getOutOfJailFree;
	private int rentMultiplier;
	private int diceRollMultiplier;
	private double rentDue;
	
	public Player()
	{
		name = "";
		boardPosition = 0;
		balance = 0.0;
		token = null;
		isActive = false;
		rollCount = 0;
		railroadsOwned = new Railroad[4];
		railroadCount = 0;
		utilitiesOwned = new Utility[2];
		utilityCount = 0;
		streetPropertiesOwned = new StreetProperty[8][3];
		streetPropertyCount = new int[8];
		for (int ii=0 ; ii < streetPropertyCount.length ; ii++)
		{
			streetPropertyCount[ii] = 0;
		}
		getOutOfJailFree = 0;
		rentDue = 0.0;
	}
	
	public Player(String name, int boardPosition, double balance, boolean isActive, Token token)
	{
		this.name = name;
		this.boardPosition = boardPosition;
		this.balance = balance;
		this.isActive = isActive;
		this.token = token;
		this.rollCount = 0;
		this.railroadsOwned = new Railroad[4];
		this.railroadCount = 0;
		this.utilitiesOwned = new Utility[2];
		this.utilityCount = 0;
		this.streetPropertiesOwned = new StreetProperty[8][3];
		this.streetPropertyCount = new int[8];
		for (int ii=0 ; ii < streetPropertyCount.length ; ii++)
		{
			this.streetPropertyCount[ii] = 0;
		}
		this.getOutOfJailFree = 0;
		this.rentDue = 0.0;

		
	}
	
	public String getName()
	{
		return name;
	}
	
	public int getBoardPosition()
	{
		return boardPosition;
	}
	
	public double getBalance()
	{
		return balance;
	}
	

	public Token getToken()
	{
		return token;
	}
	
	public boolean getIsActive()
	{
		return isActive;
	}
	
	public void makeActive()
	{
		this.isActive = true;
	}
	
	public void makeInactive()
	{
		this.isActive = false;
	}
	
	public int getRentMultiplier()
	{
		return rentMultiplier;
	}
	
	public void setRentMultiplier(int rentMultiplier)
	{
		this.rentMultiplier = rentMultiplier;
	}
	
	public int getDiceRollMultiplier()
	{
		return diceRollMultiplier;
	}
	
	public void setDiceRollMultiplier(int diceRollMultiplier)
	{
		this.diceRollMultiplier = diceRollMultiplier;
	}
	
	public double getRentDue()
	{
		return this.rentDue;
	}
	
	public void setRentDue(double rentDue)
	{
		this.rentDue = rentDue;
	}
	
	public void move(int spaces, boolean collect200)
	{
		if (this.boardPosition == 40)
		{
			this.boardPosition = 10;		// Automatically get out of jail, for now.
			this.isInJail = false;
		}
		
		this.boardPosition += spaces;
		if (this.boardPosition > 39)
		{
			this.boardPosition -= 40;
			if (collect200)
				this.balance += 200.0;
		}
	}
	
	public void move(boolean collect200, int moveToPosition)
	{
		if ((moveToPosition <= boardPosition) && (collect200))
			balance += 200.0;
		this.boardPosition = moveToPosition;
	}
	
	public void move(String nearest)
	{
		int moveToPosition = 0;
		if (nearest.equals("Railroad"))
		{
			if (this.boardPosition >= 35) moveToPosition = 5; else
			if (this.boardPosition >= 25) moveToPosition = 35; else
			if (this.boardPosition >= 15) moveToPosition = 25; else
			if (this.boardPosition >= 5) moveToPosition = 15; else
			if (this.boardPosition >= 0) moveToPosition = 5;
		} 
		if (nearest.equals("Utility"))
		{
			if ((this.boardPosition >= 12) && (this.boardPosition < 28))
				moveToPosition = 28;
			else
				moveToPosition = 12;
		}
		this.move(true, moveToPosition);
	}
	
	public void adjustBalance(double amt)
	{
		this.balance += amt;
	}
	
	public double getNetWorth()
	{
		StreetProperty streetProperty;
		double houseValue;
		double propertyValue;
		double netWorth = 0.0;
		netWorth += this.balance;
		int ii;
		for (ii=0 ; ii<railroadCount ; ii++)
			netWorth += 200.0;
		for (ii=0 ; ii<utilityCount ; ii++)
			netWorth += 150.0;
		for (int row=0 ; row<8 ; row++)
		{
			for (int column=0 ; column < 3 ; column++)
			{
				streetProperty = streetPropertiesOwned[row][column];

				try {
					propertyValue = streetProperty.getPrice();
					netWorth += propertyValue;
					houseValue = streetProperty.getHousePrice() * streetProperty.getHouseCount();
					netWorth += houseValue;
				} catch (NullPointerException e) {};
			}
		}
		return netWorth;
	}
	
	public int getPropertyCount()
	{
		int propertyCount = 0;
		int index;
		propertyCount += railroadCount;
		propertyCount += utilityCount;
		for (index=0 ; index < streetPropertyCount.length ; index++)
		{
			propertyCount += streetPropertyCount[index];
		}
		return propertyCount;
	}
	
	public Object[][] getPropertyData()
	{
		int propertyCount = getPropertyCount();
		int index;
		Railroad rr;
		Utility util;
		StreetProperty sp;
		int row = 0;
		
		Object[][] data = new Object[propertyCount][3];
		
		for (index=0 ; index<railroadCount ; index++)
		{
			rr = railroadsOwned[index];
			data[row][0] = rr.getDescription();
			data[row][1] = new ImageIcon(rr.getIconImage());
			data[row][2] = new Boolean(false);
			row++;
		}
		
		for (index=0 ; index<utilityCount ; index++)
		{
			util = utilitiesOwned[index];
			data[row][0] = util.getDescription();
			data[row][1] = new ImageIcon(util.getIconImage());
			data[row][2] = new Boolean(false);
			row++;
		}
		
		for (int propRow=0 ; propRow<8 ; propRow++)
		{
			for (int column=0 ; column < 3 ; column++)
			{
				sp = streetPropertiesOwned[propRow][column];
				try 
				{
					if (!(sp.equals(null)))
					{
						data[row][0] = sp.getDescription();
						data[row][1] = new ImageIcon(sp.getIconImage());
					//	data[row][2] = new Boolean(false);
						data[row][2] = this.isMonopoly(propRow);
						row++;
					}
				} catch (NullPointerException e) {};
			}
		}
		return data;
	}
	
	public void addRoll()
	{
		this.rollCount += 1;
	}
	
	public int getRollCount()
	{
		return rollCount;
	}
	public void resetRollCount()
	{
		rollCount = 0;
	}
	
	public void goToJail()
	{
		isInJail = true;
	}
	
	public boolean isInJail()
	{
		return isInJail;
	}
	
	public Railroad[] getRailroadsOwned()
	{
		return this.railroadsOwned;
	}
	
	public int getRailroadCount()
	{
		return railroadCount;
	}
	
	public void buyRailroad(Railroad railroad)
	{
		railroadsOwned[railroadCount] = railroad;
		railroadCount++;
	}
	
	public Utility[] getUtilitiesOwned()
	{
		return this.utilitiesOwned;
	}
	
	public int getUtilityCount()
	{
		return utilityCount;
	}
	
	public void buyUtility(Utility utility)
	{
		utilitiesOwned[utilityCount] = utility;
		utilityCount++;
	}
	
	public StreetProperty[][] getStreetPropertiesOwned()
	{
		return this.streetPropertiesOwned;
	}
	
	public int[] getStreetPropertyCount()
	{
		return streetPropertyCount;
	}
	
	public void buyStreetProperty(StreetProperty streetProperty, int group, int position)
	{
		streetPropertiesOwned[group][position] = streetProperty;
		streetPropertyCount[group]++;
	}
	
	public int getStreetPropertyCount(int group)
	{
		return streetPropertyCount[group];
	}
	
	public boolean isMonopoly(int group)
	{
		int max;
		
		if ((group == 0) || (group == 7))
			max = 2;
		else
			max = 3;
		
		if (streetPropertyCount[group] == max)
			return true;
		else
			return false;
	}
	
	public void addGetOutOfJailCard()
	{
		this.getOutOfJailFree++;
	}
	
	public int getGetOutOfJail()
	{
		return this.getOutOfJailFree;
	}
	
	public void rollAndMove(GameState gameState)
	{
		Die d1 = gameState.getDie1();
		Die d2 = gameState.getDie2();
		
		d1.roll();
		d2.roll();
		
		int faceValue = d1.getFaceValue() + d2.getFaceValue();
		rollCount++;
		
		if ((rollCount == 3) && (d1.getFaceValue() == d2.getFaceValue()))
		{
			goToJail();
			move(false, 40);
		}
		else
			move(faceValue, true);
	}
	
	public void landOnCard(GameBoardSpace[] board, GameState gameState)
	{
		Card draw = new Card();
		boardPosition = this.getBoardPosition();
		GameBoardSpace space = board[boardPosition];
		
		String currentType = space.getType();

		int cardSwitch = 0;
		if (currentType.equals("Community Chest")) cardSwitch = 1;
		if (currentType.equals("Chance")) cardSwitch = 2;
		
		switch (cardSwitch)
		{
		case 1:  draw = gameState.getCommunityChest().drawCard(); break;
		case 2:  draw = gameState.getChance().drawCard();	break;
		}
		draw.execute(gameState);
		this.rentMultiplier = draw.getRentMultiplier();
		this.diceRollMultiplier = draw.getDiceRollMultiplier();
	}
	
	public boolean landOnProperty(GameBoardSpace[] board, GameState gameState)
	{
		Player activePlayer = gameState.getActivePlayer();
		Player owner = null;
		GameBoardSpace space = board[activePlayer.getBoardPosition()];
		String currentType = space.getType();

		int rentMultiplier = activePlayer.getRentMultiplier();
		int diceRollMultiplier = activePlayer.getDiceRollMultiplier();
		
		double rent = 0.0;
		boolean isAvailable = false;
		if (currentType.equals("Railroad"))
		{
			Railroad railroad = space.getRailroad();
			owner = railroad.getOwner();
			if ((railroad.getOwner() != null) && (railroad.getOwner() != activePlayer))
				rent = railroad.getRent(gameState, rentMultiplier);
			if (railroad.isAvailable())
				isAvailable = true;
		}
		if (currentType.equals("Utility"))
		{
			Utility utility = space.getUtility();
			owner = utility.getOwner();
			if ((utility.getOwner() != null) && (utility.getOwner() != activePlayer))
				rent = utility.getRent(gameState, rentMultiplier);
			if (utility.isAvailable())
				isAvailable = true;
		}
		if (currentType.equals("Street Property"))
		{
			StreetProperty streetProperty = space.getStreetProperty();
			owner = streetProperty.getOwner();
			if ((streetProperty.getOwner() != null) && (streetProperty.getOwner() != activePlayer))
				rent = streetProperty.getRent(gameState, rentMultiplier);
			if (streetProperty.isAvailable())
				isAvailable = true;
		}
		
			
		if (diceRollMultiplier != 0)
			rent = (double) diceRollMultiplier * (gameState.getDie1().getFaceValue() + gameState.getDie2().getFaceValue());

		if ((activePlayer != owner) && (owner != null))
		{
			JOptionPane.showMessageDialog(null, "Property is owned by " + owner.getName() + ".\n " +
				"Rent due:  " + rent + ".");
		}  else
		{
			activePlayer.setDiceRollMultiplier(0);
			activePlayer.setRentMultiplier(0);
		}
		
		this.rentDue = rent;
		
		return isAvailable;
	}

	
	public boolean purchaseProperty(GameBoardSpace space)
	{
		double balance;
		double price = 0.0;
		Railroad railroad = null;
		Utility utility = null;
		StreetProperty streetProperty = null;
		
		balance = this.balance;
		
		String propertyName = space.getDescription();
		String monopolyText = "";
		int propertySwitch = 0;
		if (space.getType().equals("Railroad")) propertySwitch = 1;
		if (space.getType().equals("Utility")) propertySwitch = 2;
		if (space.getType().equals("Street Property")) propertySwitch = 3;
		
		switch (propertySwitch)
		{
		case 1:
			railroad = space.getRailroad();
			price = railroad.getPrice();
			break;
		case 2:
			utility = space.getUtility();
			price = utility.getPrice();
			break;
		case 3:
			streetProperty = space.getStreetProperty();
			price = streetProperty.getPrice();
			break;
		}
		
		if (balance >= price)
		{
			switch (propertySwitch)
			{
			case 1:  railroad.purchase(this);  break;
			case 2:  utility.purchase(this);  break;
			case 3:  
				streetProperty.purchase(this);  
				if (streetProperty.getOwner().isMonopoly(streetProperty.getGroup()))
					monopolyText = "You have a monopoly!";
				break;
			}

			JOptionPane.showMessageDialog(null, "Congratulations!  You purchased " + propertyName + ".\n\n" + monopolyText);
			return new Boolean(true);
		} else
		{
			JOptionPane.showMessageDialog(null, "Insufficient Funds.");
			return new Boolean(false);
		}
	}
	
	public boolean payRent(GameState gameState, int rentMultiplier, int diceRollMultiplier)
	{	
		Player owner = new Player();
		double rent = 0.0;
		GameBoard board = gameState.getGameBoard();
		GameBoardSpace[] spaces = board.getSpaceArray();
		GameBoardSpace space = spaces[this.getBoardPosition()];
		
		String type = space.getType();
		
		int propertySwitch = 0;
		if (type.equals("Railroad")) propertySwitch = 1;
		if (type.equals("Utility")) propertySwitch = 2;
		if (type.equals("Street Property")) propertySwitch = 3;
		
		switch (propertySwitch)
		{
		case 1:
			owner = space.getRailroad().getOwner();
			rent = space.getRailroad().getRent(gameState, rentMultiplier);
			break;
		case 2:
			owner = space.getUtility().getOwner();
			rent= space.getUtility().getRent(gameState, rentMultiplier);
			break;
		case 3:
			owner = space.getStreetProperty().getOwner();
			rent = space.getStreetProperty().getRent(gameState, rentMultiplier);
			break;
		}
		
		if (diceRollMultiplier != 0)
			rent = (double) diceRollMultiplier * (gameState.getDie1().getFaceValue() + gameState.getDie2().getFaceValue());
		
		if (this.getBalance() < rent)
		{
			JOptionPane.showMessageDialog(null, "Insufficient Funds.");
			return new Boolean(false);
		}
		else
		{
			owner.adjustBalance(rent);
			this.adjustBalance(0-rent);
			return new Boolean(true);

		}	
	}
}
